/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.dwh.trigger;

import java.io.IOException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import static org.dwh.trigger.Out.*;
import static org.dwh.trigger.Configure.*;

/**
 *
 * @author Jose Carlos Palma
 * @version v1.0.0
 */
public class ServerSocket extends ThreadSocket {

    /**
     * Es el server socket.
     */
    private java.net.ServerSocket server;
    /**
     * Lista de clientes de tipo origen(Source).
     */
    private ClientSocket[] sources = new ClientSocket[255];
    /**
     * Cliente de tipo destino(Target).
     */
    private ClientSocket[] targets = new ClientSocket[255];
    /**
     * Es el número de puerto del server socket.
     */
    private int serverPort;

    /**
     * Crea una instancia de ServerSocket.
     * @param name es el nombre del servicio.
     * @param serverPort es el número de puerto por el cual va a escuchar a los 
     *                   clientes origen
     * @param targetIP es la IP del cliente destino al cual le va enviar los trigger.
     * @param targetPort es el número de puerto del enlace de red del cliente destino.
     */
    public ServerSocket(String name, int serverPort) {
        super(name);
        setServer();
        this.serverPort = serverPort;
    }
    
    private void createDefaultQueue(){
        String queueName = getString("queue.name");
        int queuePort = getInt("queue.port");
        String queueIP = getString("queue.ip");
        targets[0] = new ClientSocket(queueName, queueIP, queuePort);
        info(targets[0].toString());
        
        //Inicia la cola por defecto
        targets[0].start();
    }

    private void createQueue(){
        
    }

    /**
     * Se encarga de crea un enlace de red (servidor) con las SLU (clientes de 
     * tipo origen), para recibir los triggers que posteriormente son depositados a 
     * los clientes detinos.
     */
    @Override
    public void core() {

        createDefaultQueue();

        //Inicia el ServerSocket
        info("Iniciando ServerSocket " + name + "...");
        try {
            server = new java.net.ServerSocket(serverPort);
            server.setSoTimeout(10000);
        } catch (IOException ex) {
            error("No se pude iniciar ServerSocket " + name + ", " + ex.getMessage());
            System.exit(1);
        }
        info("ServerSocket " + name + " [OK]");

        while (isRunning()) {
            try {
                info("ServerSocket " + name + " esperando SLU...");
                Socket client = server.accept();
                String ip =  client.getInetAddress().getHostAddress();
                int indx = getFreeSource();
                if( indx == -1 ){
                    error("ServerSocket " + name + " [FullQueueException] no pudo establecer "
                            + "conexion con la SLU " + ip
                            + ", la cola esta llena");
                    pause(20000);
                    continue;
                }
                String[] info = getSDPInfo(ip);
                info("ServerSocket " + name + ", se conecto con " + Arrays.toString(info));
                sources[indx] = new ClientSocket(info[0] + "-" + info[1], client);
                sources[indx].start();
            } catch (SecurityException ex) {
                error("ServerSocket " + name + " [SecurityException] no pudo establecer "
                        + "conexion con las SLU, " + ex.getMessage());
            } catch (SocketTimeoutException ex) {
                pause(10000);
            } catch (IOException ex) {
                error("ServerSocket " + name + " [IOException] erorr de I/O "
                        + "con las SLU, " + ex.getMessage());
            }
        }
        info("Cerrando ServerSocket " + name + "...");
        try {
            server.close();
        } catch (IOException ex) {
        }
        
        //Cierra los clientes origenes
        info("ServerSocket " + name + " esta cerrando los clientes origenes...");
        for(ClientSocket source: sources){
            if( source == null ) continue;
            info("ServerSocket " + name + " cerrando " + source.toString());
            source.halt();
            while( !source.isShutDown() ){
                pause(500);
            }
        }
        
        //Cierra los clientes destinos
        info("ServerSocket " + name + " esta cerrando los clientes destinos...");
        for(ClientSocket target: targets){
            if( target == null ) continue;
            info("ServerSocket " + name + " cerrando " + target.toString());
            target.halt();
            while( !target.isShutDown() ){
                pause(500);
            }
        }

    }
    
    private int getFreeSource(){
        for( int i = 0; i < sources.length; i++ ){
            if( sources[i] == null )
                return i;
        }
        return -1;
    }
}
